package com.meta.nd.service.impl;

import com.meta.cache.NdCacheService;
import com.meta.common.CommonInfo;
import com.meta.common.ConstDef;
import com.meta.nd.annotation.utils.NdAnnotationUtil;
import com.meta.nd.dao.NvFilterDAO;
import com.meta.nd.filter.bo.FilterDef;
import com.meta.nd.filter.bo.FilterParamDef;
import com.meta.nd.filter.vo.FilterByDefVo;
import com.meta.nd.filter.vo.FilterFd;
import com.meta.nd.filter.vo.FilterResultVo;
import com.meta.nd.filter.vo.ResultFd;
import com.meta.nd.service.NvFilterService;
import com.meta.nd.vo.*;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Service
public class NvFilterServiceImpl implements NvFilterService {
    @Resource
    NdCacheService ndCacheService;
    @Resource
    NvFilterDAO nvFilterDAO;

    @Override
    public FilterResultVo filterNvs(CommonInfo commonInfo, FilterByDefVo filterByDefVO) {
        FilterDef filterDef = this.getFilterDef(filterByDefVO.getFilterDefCode());
        FilterDef targetFilterDef = this.rebuildFilterDef(filterByDefVO,filterDef);
        return this.filterNvs(commonInfo,targetFilterDef);
    }

@Override
public FilterResultVo filterNvs(CommonInfo commonInfo, FilterDef filterDef){
    return this.filterNvsByParamDef(commonInfo,filterDef.toFilterParamDef());
}

@Override
public FilterResultVo filterNvsByParamDef(CommonInfo commonInfo, FilterParamDef filterDef){
    ListQueryResult<Nv> nvsMsg = this.nvFilterDAO.filterNvs(filterDef);
    FilterResultVo filterResultVo = new FilterResultVo();
    filterResultVo.setTotal(nvsMsg.getTotalCount());
    filterResultVo.setNvs(nvsMsg.getResult());
    return filterResultVo;
}

private FilterDef getFilterDef(String filterDefCode){
    Nv mv = this.ndCacheService.getMv(ConstDef.FILTER_FUNCTION,filterDefCode);
    if ( mv == null )
        throw new RuntimeException(String.format("不存在的查询定义:%s", filterDefCode));
    FilterDef filterDef = NdAnnotationUtil.nv2Object(mv, FilterDef.class);
    filterDef.setDefault();filterDef.sortFd();
    Nd rootNd = ndCacheService.getNd(filterDef.getTargetNdCode());
    Nd returnNd = ndCacheService.getNd(filterDef.getReturnNdCode());
    for(FilterFd filterFd : filterDef.getFilterFds()){
        if (StringUtils.isEmpty(filterFd.getNdName()))
            filterFd.setNdName(returnNd.getNdName());
        if ( filterFd.getFdName().equals(ConstDef.FD_NAME_META_ND_CODE)){
            filterFd.setDataType(ConstDef.DATA_TYPE_STRING);
        }
        else {
            Nd currentNd = rootNd.getDescendantByName(filterFd.getNdName());
            Fd fd = currentNd.getFdByName(filterFd.getFdName());
            filterFd.setDataType(fd.getDataType());
        }
    }
    for(ResultFd resultFd : filterDef.getResultFds()){
        if ( resultFd.isExpression())
            continue;
        if (StringUtils.isEmpty(resultFd.getNdName())) {
            resultFd.setNdName(returnNd.getNdName());
        }
        Nd currentNd = rootNd.getDescendantByName(resultFd.getNdName());
        if ( resultFd.getFdName().equals(ConstDef.FD_NAME_ID)
            || resultFd.getFdName().equals(ConstDef.FD_NAME_PARENT_ID)){
            resultFd.setDataType(ConstDef.DATA_TYPE_LONG);
        }
        else if(resultFd.getFdName().equals(ConstDef.FD_NAME_META_ND_CODE)){
            resultFd.setDataType(ConstDef.DATA_TYPE_STRING);
        }
        else {
            Fd fd = currentNd.getFdByName(resultFd.getFdName());
            resultFd.setDataType(fd.getDataType());
        }
    }
    List<String> resultFdNames = filterDef.getResultNames(returnNd.getNdName());
    if (!resultFdNames.contains(ConstDef.FD_NAME_ID)){
        ResultFd resultFd = new ResultFd(ConstDef.FD_NAME_ID,null,returnNd.getNdName());
        resultFd.setDataType(ConstDef.DATA_TYPE_LONG);
        filterDef.addResultFd(resultFd);
    }
    if (!resultFdNames.contains(ConstDef.FD_NAME_PARENT_ID)){
        ResultFd resultFd = new ResultFd(ConstDef.FD_NAME_PARENT_ID,null,returnNd.getNdName());
        resultFd.setDataType(ConstDef.DATA_TYPE_LONG);
        filterDef.addResultFd(resultFd);
    }
    if (!resultFdNames.contains(ConstDef.FD_NAME_META_ND_CODE)){
        ResultFd resultFd = new ResultFd(ConstDef.FD_NAME_META_ND_CODE,null,returnNd.getNdName());
        resultFd.setDataType(ConstDef.DATA_TYPE_STRING);
        filterDef.addResultFd(resultFd);
    }
    return filterDef;
}

private FilterDef rebuildFilterDef(FilterByDefVo filterByDefVO,FilterDef filterDef){
    FilterDef targetFilterDef = filterDef.clone();
    targetFilterDef.getFilterFds().clear();
    for( FilterFd filterFd : filterDef.getFilterFdWithFixedValue()){
        filterFd.setValue(filterFd.getFixedValue());
        targetFilterDef.getFilterFds().add(filterFd);
    }
    for( FilterFd filterFd : filterByDefVO.getFilterFds()){
        if ( filterDef.getFilterFdByFdAndAliasName(filterFd.getFinalName())!=null && !targetFilterDef.containFilterFd(filterFd.getFinalName())){
            targetFilterDef.getFilterFds().add(filterFd);
            for(FilterFd tmpFilterFd : filterDef.getFilterFds()){
                if(filterFd.getFinalName().equals(tmpFilterFd.getFinalName())) {
                    filterFd.setLogicalOperator(tmpFilterFd.getLogicalOperator());
                    filterFd.setNdName(tmpFilterFd.getNdName());
                }
            }
        }
    }
    targetFilterDef.setCount(filterByDefVO.getCount());
    targetFilterDef.setStartNo(filterByDefVO.getStartNo());
    return targetFilterDef;
}


    @Override
    public List<Map<String,Object>> filterRecordMap(CommonInfo commonInfo, FilterDef filterDef){
        return this.nvFilterDAO.filterRecordMap(filterDef.toFilterParamDef());
    }

    @Override
    public  List<Map<String,Object>> filterRecordMap(CommonInfo commonInfo, String sql, Map<String,Object> parmMap){

        return this.nvFilterDAO.filterRecordMap(commonInfo,sql,parmMap);

    }

}
